package acs.bridge;

import acs.bridge.dao.BridgeDAOImpl;
import acs.bridge.model.bm_file_model;
import org.apache.log4j.Logger;

import java.io.*;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;


/**
 * home
 * ACS
 * User: stas
 * Date: 24.05.13
 * Time: 17:54
 */
public class bm_load_file implements BridgeModuleInterface, BridgeModuleExtInterface {
    static String version = "2";
    Logger logger = Logger.getLogger(this.getClass().getName());
    public static BridgeDAOImpl bridgeDAOImpl;
    final public String ctlName = "bm_load_file.ctl";
    final public String logName = "bm_load_file.log";

    /* Путь до временного каталог */
    private String tempFilePath;

    private String controlFile;
    private bm_load_file_interface load_file_interface;
    private acs.bridge.dao.bm_load_fileImpl bm_load_fileImpl;
    private String deleteTempFile = "1";

    public String getPatternAfterProcessing() {
        return patternAfterProcessing;
    }

    public void setPatternAfterProcessing(String patternAfterProcessing) {
        this.patternAfterProcessing = patternAfterProcessing;
    }

    private String patternAfterProcessing = ".*";

    public String getLoadFile() {
        return loadFile;
    }

    public void setLoadFile(String loadFile) {
        this.loadFile = loadFile;
    }

    private String loadFile = "1";

    public String getUnzipFile() {
        return unzipFile;
    }

    public void setUnzipFile(String unzipFile) {
        this.unzipFile = unzipFile;
    }

    private String unzipFile = "0";

    public String getDoFinal() {
        return doFinal;
    }

    public void setDoFinal(String doFinal) {
        this.doFinal = doFinal;
    }

    private String doFinal = "0";
    private String raw_table_postfix;
    private String metaTag;

    public String getReloadFile() {
        return reloadFile;
    }

    public void setReloadFile(String reloadFile) {
        this.reloadFile = reloadFile;
    }

    private String reloadFile = "1";
    private String copyFile = "1";

    public void setCopyFile(String copyFile) {
        this.copyFile = copyFile;
    }

    public String getCopyFile() {
        return copyFile;
    }


    public static void main(String[] args) {
        // bm_load_file l_test = new bm_load_file();
        // l_test.execute("BRIDGE", "FILE_NAME", new BigDecimal(10));


        //l_test.setLoad_file_interface(new bm_load_file_path());
        // l_test.execute_meta_start("KSSS", "SOBJ");


    }

    /* Запускается перед запуском интерфейса */
    public void initial_processing() {

    }

    /* Запускается после обработки интерфейса */
    public void final_processing(BigDecimal taskID) {
        //  logger.info("Final doFinal=" + doFinal +",metaTag=" + metaTag);
      /*  if (doFinal.equals("1") && metaTag != null) {
            logger.info("Final processing started. {final_" + metaTag.toLowerCase() + "}");
            bm_load_fileImpl.final_processing(taskID, metaTag);
            logger.info("Final processing finished.");

        }  */
    }

    public void setBridgeDAOImpl(BridgeDAOImpl bridgeDAOImpl) {
        this.bridgeDAOImpl = bridgeDAOImpl;
    }

    public static boolean removeDirectory(File directory) {

        // System.out.println("removeDirectory " + directory);

        if (directory == null)
            return false;
        if (!directory.exists())
            return true;
        if (!directory.isDirectory())
            return false;

        String[] list = directory.list();

        // Some JVMs return null for File.list() when the
        // directory is empty.
        if (list != null) {
            for (int i = 0; i < list.length; i++) {
                File entry = new File(directory, list[i]);

                //        System.out.println("\tremoving entry " + entry);

                if (entry.isDirectory()) {
                    //if (!removeDirectory(entry))
                    return false;
                } else {
                    if (!entry.delete())
                        return false;
                }
            }
        }

        return true;
    }

    @Override
    public void execute(String a_group_tag, String a_meta_tag, BigDecimal a_raw_id, String a_module_tag) throws BridgeModuleException {
        //bridgeDAOImpl.prc_msg("Test", "E", "", 100, "BridgeModuleExecute_-1");
        logger.info("BridgeModule " + this.getClass().getName() + " ver." + version + " {raw_id=" + a_raw_id + "}");
        metaTag = a_meta_tag;
        /* получить название файла */
        String l_filename = bridgeDAOImpl.get_string_field_by_id(a_group_tag, a_meta_tag, a_raw_id, "FILE_NAME", "RAW");

        /* получить размер файла */
        String l_filesize = bridgeDAOImpl.get_string_field_by_id(a_group_tag, a_meta_tag, a_raw_id, "FILE_SIZE", "RAW");

        String l_error_text = null;
        List<String> l_filename_list = new ArrayList<String>();

        File folder = new File(tempFilePath);
        File tempFile = null;
        try {
        /* Копируем файл во временный каталог */

            if (copyFile.equals("1")) {
                logger.info("Start copy file");
                /* Проверяем наличие файла в каталоге */
                tempFile = new File(tempFilePath + l_filename);
                if (!tempFile.exists() || getReloadFile().equals("1")) {
                    logger.info("Reload file");
                    if (tempFile.exists())
                        tempFile.delete();
                    load_file_interface.get_file(l_filename, tempFilePath);
                    tempFile = new File(tempFilePath + l_filename);
                }
                l_filename_list.add(l_filename);
                logger.info("Finish copy file");
            }

            if (tempFile == null) {
                if (tempFile.exists()) {
                    long l_size_before = Long.getLong(l_filesize);
                    long l_size_after = tempFile.length();
                    if (l_size_before != l_size_after) {
                        throw new BridgeModuleException("File size error {filename=" + l_filename + ",size_before=" + l_size_before + ",size_after=" + l_size_after + "}");
                    }
                }
            }

        /* Если необходимо разархивируем */
            if (unzipFile.equals("1")) {
                logger.info("Start unzip file " + l_filename);
                l_filename_list.clear();
                //create output directory is not exists

                if (!folder.exists()) {
                    folder.mkdir();
                }

                //get the zip file content
                ZipInputStream zis =
                        new ZipInputStream(new FileInputStream(tempFilePath + File.separator + l_filename));
                //get the zipped file list entry
                ZipEntry ze = zis.getNextEntry();
                byte[] buffer = new byte[1024];

                while (ze != null) {

                    String fileName = ze.getName();
                    File newFile = new File(tempFilePath + File.separator + fileName);


                    logger.info("file unzip : " + newFile.getAbsoluteFile());
                    l_filename_list.add(newFile.getName());

                    //create all non exists folders
                    //else you will hit FileNotFoundException for compressed folder
                    new File(newFile.getParent()).mkdirs();

                    FileOutputStream fos = new FileOutputStream(newFile);

                    int len;
                    while ((len = zis.read(buffer)) > 0) {
                        fos.write(buffer, 0, len);
                    }

                    fos.close();
                    ze = zis.getNextEntry();
                }
                logger.info("Finish unzip file " + l_filename);
                zis.closeEntry();
                zis.close();


            }


            Iterator l_it = l_filename_list.iterator();
            while (l_it.hasNext()) {
                String l_cur_file_name = (String) l_it.next();

                if (Pattern.matches(getPatternAfterProcessing(), l_cur_file_name) || getPatternAfterProcessing().equals("")) {


                    String l_controlFile = controlFile.replace("@filename@", l_cur_file_name);

        /* Создаем контрол файл для загрузки через sqlldr */
                    if (loadFile.equals("1")) {

                        File l_cFile = new File(tempFilePath + ctlName);

                        logger.info(l_controlFile);
                        FileWriter l_fileWriter = new FileWriter(l_cFile);
                        try {
                            l_fileWriter.write(l_controlFile);

                        } finally {
                            l_fileWriter.close();
                        }


         /* Запускаем sqlldr */

                        String l_exec = "sqlldr " + bridgeDAOImpl.getDb_username() + "@" + bridgeDAOImpl.getDb_name() + "/" + bridgeDAOImpl.getDb_password() + " control=" + "bm_load_file.ctl log=" + "bm_load_file.log";
                        //logger.info(l_exec);
                        Process proc = null;
                        try {
                            logger.info(folder.getAbsolutePath());
                            proc = Runtime.getRuntime().exec(l_exec, null, folder);

                            logger.info(proc.waitFor());
                        } catch (InterruptedException e) {
                            logger.error(e.getMessage());
                            throw new BridgeModuleException(e.getMessage());

                        }


        /* Читаем log файл и достаем ошибки если были */
                        BufferedReader br = new BufferedReader(new FileReader(tempFilePath + logName));

                        try {
                            StringBuilder sb = new StringBuilder();
                            String line = br.readLine();

                            while (line != null) {
                                if ((line.contains("SQL*Loader-") || line.contains("Rejected")) && l_error_text == null) {
                                    l_error_text = line;
                                    logger.info(line);

                                }

                                if ((line.contains("ORA-") || line.contains("LPX-")) && l_error_text != null) {
                                    l_error_text = l_error_text + "\n" + line + "\n";
                                    logger.info(line);
                                    //break;
                                }

                                sb.append(line);
                                sb.append("\n");
                                line = br.readLine();
                            }
                        } finally {
                            br.close();
                        }
                        logger.info("Finish load file");
                    }
                }
            }
        } catch (
                IOException e
                )

        {
            throw new BridgeModuleException(e.getMessage());
        } catch (
                BridgeException e
                )

        {
            throw new BridgeModuleException(e.getMessage());
        } finally

        {

             /* Удаляем файлы из временного каталога */
            if (getDeleteTempFile().equals("1"))
                removeDirectory(new File(tempFilePath));

        }

        if (l_error_text != null)
            throw new

                    BridgeModuleException(l_error_text);

    }

    public String getTempFilePath() {
        return tempFilePath;
    }

    public void setTempFilePath(String tempFilePath) {
        this.tempFilePath = tempFilePath;
    }

    public void setControlFile(String controlFile) {
        this.controlFile = controlFile;
    }

    public String getControlFile() {
        return controlFile;
    }


    public void setLoad_file_interface(bm_load_file_interface load_file_interface) {
        this.load_file_interface = load_file_interface;
    }

    public bm_load_file_interface getLoad_file_interface() {
        return load_file_interface;
    }

    @Override
    public void execute_meta_start(String a_group_tag, String a_meta_tag) {
        logger.info("execute_meta_start");

        String l_table_name = bridgeDAOImpl.fnc_schema_by_group(a_group_tag, a_meta_tag) + "." + "FBI_RAW_" + a_meta_tag;

        if (raw_table_postfix != null)
            l_table_name = l_table_name + raw_table_postfix;

        List<bm_file_model> l_bm_file_model_list = load_file_interface.get_directory_list();

        bm_file_model l_bm_file_model = null;
        Iterator l_bm_file_model_itr = l_bm_file_model_list.iterator();

        while (l_bm_file_model_itr.hasNext()) {
            l_bm_file_model = (bm_file_model) l_bm_file_model_itr.next();


            if (bridgeDAOImpl.fnc_get_fr_id_exists(l_bm_file_model.getFr_id(), a_group_tag, a_meta_tag) == 0) {

                bm_load_fileImpl.insertRawFile(l_table_name, l_bm_file_model.getFr_id(), l_bm_file_model.getFile_name(), l_bm_file_model.getFile_path(), l_bm_file_model.getLast_modified(), l_bm_file_model.getFile_size());
                logger.info("File '" + l_bm_file_model.getFr_id() + "' processed.");
            }

        }

        try {
            bm_load_fileImpl.getJdbcTemplate().getDataSource().getConnection().commit();
        } catch (SQLException e) {
            logger.error(e.getMessage());
        }

    }

    public void execute_meta_finish(String a_group_tag, String a_meta_tag) {
        logger.info("execute_meta_finish");
    }


    public void setBm_load_fileImpl(acs.bridge.dao.bm_load_fileImpl bm_load_fileImpl) {
        this.bm_load_fileImpl = bm_load_fileImpl;
    }

    public acs.bridge.dao.bm_load_fileImpl getBm_load_fileImpl() {
        return bm_load_fileImpl;
    }

    public void setDeleteTempFile(String deleteTempFile) {
        this.deleteTempFile = deleteTempFile;
    }

    public String getDeleteTempFile() {
        return deleteTempFile;
    }

    public void setRaw_table_postfix(String raw_table_postfix) {
        this.raw_table_postfix = raw_table_postfix;
    }

    public String getRaw_table_postfix() {
        return raw_table_postfix;
    }
}